import Dep from "./observer/dep";
import { observe } from "./observer/index";
import Watcher from "./observer/watcher";
import { isFunction } from "./utils";

export function initState(vm) {
  const opts = vm.$options;
  if (opts.props) {
    initProps(vm);
  }
  if (opts.methods) {
    initMethods(vm);
  }
  if (opts.data) {
    initData(vm);
  }

  if (opts.computed) {
    initComputed(vm, opts.computed);
  }
  if (opts.watch) {
    initWatch(vm, opts.watch);
  }
}

export function stateMixin(Vue) {
  Vue.prototype.$watch = function (key, handler, options = {}) {
    options.user = true; // 用户自己的watcher 区分渲染watcher

    let watcher = new Watcher(this, key, handler, options);
    if (options.immediate) {
      handler(watcher.value);
    }
  };
}

function initProps(vm) {}

function initMethods(vm) {}

function initData(vm) {
  let data = vm.$options.data;
  // 这时候vm 和data没有关系。 通过_data关联
  data = vm._data = isFunction(data) ? data.call(vm) : data;
  for (let key in data) {
    proxy(vm, "_data", key);
  }
  // 数据的劫持方案 对象Object.defineProperty 数组单独处理
  observe(data);
}

function proxy(vm, data, key) {
  Object.defineProperty(vm, key, {
    get() {
      return vm[data][key];
    },
    set(newVal) {
      vm[data][key] = newVal;
    },
  });
}

// 当在页面中直接写fullName时， fullName不会去收集渲染watcher 因为fullnamem没有dep 没有收集功能
// firstName 是在计算属性中使用的，所以他回去收集计算属性watcher 没有收集到渲染watcher
// 计算属性中的值应该记录 计算属性watcher 和 渲染watcher
// Dep.target上赋值一个渲染watcher 又将Dep.target设置为计算属性watcher

// 渲染watcher 取fullName 计算属性watcher => (firstName, lastName) 让firstName lastName继续收集渲染watcher
function initComputed(vm, computed) {
  const watchers = (vm._computedWatchers = Object.create(null));
  for (let key in computed) {
    const userDef = computed[key];
    const getter = typeof userDef === "function" ? userDef : userDef.get;
    watchers[key] = new Watcher(vm, getter, () => {}, {
      lazy: true, // 默认不执行
    });
    defineComputed(vm, key, userDef);
  }
}

function defineComputed(vm, key, userDef) {
  let sharedProperty = {
    enumerable: true,
    configurable: true,
  };
  if (typeof userDef === "function") {
    sharedProperty.get = createComputedGetter(key);
  } else {
    sharedProperty.get = createComputedGetter(key);
    sharedProperty.set = userDef.set;
  }
  Object.defineProperty(vm, key, sharedProperty);
}

function createComputedGetter(key) {
  return function computedGetter() { // getter
    // this ? vm 谁取值 this就是谁
    const watcher = this._computedWatchers[key]
    // 判断是否重新取值
    if (watcher.dirty) {
      watcher.evaluate()
    }

    // getter 返回值
    return watcher.value
  };
}

// function createComputedGetter(key) {
//   // 取计算属性的值，走的就是这个函数
//   return function computedGetter() {
//     // 通过key 可以拿到对应watcher, 这个this._computedWatchers包含着所有的计算属性watcher
//     let watcher = this._computedWatchers[key];
//     // 根据dirty 脏了的话，就是计算属性，需要重新求值
//     if (watcher.dirty) {
//       watcher.evaluate(); // this.get()
//     }
//     // 如果当前取值万后， Dep.target还有值，需要继续向上收集
//     if (Dep.target) {
//       // 渲染watcher
//       // 计算属性watcher 内部有两个Dep  firstName lastName
//       // 让计算属性做一个依赖收集  watcher 里对应了多个dep
//       watcher.depend();
//     }
//     return watcher.value;
//   };
// }

function initWatch(vm, watch) {
  for (let key in watch) {
    let handler = watch[key];
    if (Array.isArray(handler)) {
      for (let i = 0; i < handler.length; i++) {
        handler[i];
        createWatcher(vm, key, handler[i]);
      }
    } else {
      handler;
      createWatcher(vm, key, handler);
    }
  }
}

function createWatcher(vm, key, handler) {
  // new Watcher(vm, key, handler);
  return vm.$watch(key, handler);
}
